package domain

import (
	"context"
	"database/sql"
)

type UnitOfWorkStore interface {
	Demo() *DemoRepository
	AuditLog() *AuditLogRepository
}
type unitOfWorkStore struct {
	demoRepository     *DemoRepository
	auditLogRepository *AuditLogRepository
}

func (store *unitOfWorkStore) Demo() *DemoRepository {
	return store.demoRepository
}
func (store *unitOfWorkStore) AuditLog() *AuditLogRepository {
	return store.auditLogRepository
}

type UnitOfWork struct {
	db *sql.DB
}

func NewUnitOfWork(db *sql.DB) *UnitOfWork {
	return &UnitOfWork{
		db: db,
	}
}

func (uow *UnitOfWork) Do(ctx context.Context, options *sql.TxOptions, fn func(UnitOfWorkStore) error) error {
	var tx, err = uow.db.BeginTx(ctx, options)
	if err != nil {
		return err
	}
	defer func(tx *sql.Tx) {
		err := tx.Rollback()
		if err != nil {
			panic(err.Error())
		}
	}(tx)

	var store = &unitOfWorkStore{
		demoRepository:     NewDemoRepository(tx),
		auditLogRepository: NewAuditLogRepository(tx),
	}

	if err = fn(store); err != nil {
		return err
	}

	if err = tx.Commit(); err != nil {
		return err
	}

	return nil
}
